// Package adapter 提供各种音频播放器适配器
package adapter

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"sync"
	"syscall"
	"time"

	"gitee.com/rw555/fdsmastergo/pkg/audioplayer"
	"gitee.com/rw555/fdsmastergo/pkg/logger"
)

// NewAplayPlayer 创建一个基于aplay的播放器实例
func NewAplayPlayer(config *audioplayer.Config) (audioplayer.AudioPlayer, error) {
	return NewAPlayAdapter(config)
}

// APlayAdapter 实现了基于aplay命令行工具的音频播放适配器
type APlayAdapter struct {
	mutex            sync.Mutex
	cmd              *exec.Cmd
	status           audioplayer.PlaybackStatus // "playing", "paused", "stopped"
	volume           float64                    // 音量 0.0-1.0
	position         float64                    // 当前播放位置(秒)
	duration         float64                    // 总时长(秒)
	source           *audioplayer.AudioSource
	playlist         []*audioplayer.AudioSource
	playlistMutex    sync.RWMutex
	supportedFormats []audioplayer.AudioFormat
	config           *audioplayer.Config
	startTime        time.Time
	pausedAt         time.Time
	totalPausedTime  time.Duration
	eventHandlers    map[audioplayer.PlaybackEventType][]audioplayer.PlaybackEventHandler
}

// NewAPlayAdapter 创建一个新的aplay适配器实例
func NewAPlayAdapter(config *audioplayer.Config) (*APlayAdapter, error) {
	// 检查aplay命令是否存在
	aplayPath := config.PlayerPath
	if aplayPath == "" {
		aplayPath = "aplay"
	}

	_, err := exec.LookPath(aplayPath)
	if err != nil {
		return nil, fmt.Errorf("aplay命令不存在: %v", err)
	}

	// 创建并初始化适配器
	adapter := &APlayAdapter{
		status:           audioplayer.StatusStopped,
		volume:           config.DefaultVolume,
		position:         0,
		duration:         0,
		source:           nil,
		playlist:         make([]*audioplayer.AudioSource, 0),
		supportedFormats: []audioplayer.AudioFormat{audioplayer.FormatWAV, audioplayer.FormatRAW},
		config:           config,
		eventHandlers:    make(map[audioplayer.PlaybackEventType][]audioplayer.PlaybackEventHandler),
	}

	return adapter, nil
}

// Play 播放指定的音频文件
func (a *APlayAdapter) Play(ctx context.Context, source audioplayer.AudioSource) error {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	// 如果当前有正在播放的文件，先停止
	if a.cmd != nil && a.cmd.Process != nil {
		a.stopPlayback()
	}

	// 复制AudioSource以确保不会被外部修改
	sourceCopy := source

	// 重置计时和状态
	a.position = 0
	a.duration = 0
	a.source = &sourceCopy
	a.startTime = time.Now()
	a.totalPausedTime = 0

	// 检查文件是否存在
	if _, err := os.Stat(source.Path); os.IsNotExist(err) {
		return fmt.Errorf("文件不存在: %s", source.Path)
	}

	// 估算文件时长（后续可以用更准确的方式获取）
	fileInfo, err := os.Stat(source.Path)
	if err == nil {
		// 粗略估算：假设是16位立体声44.1kHz的WAV文件
		// 则每秒数据量约为: 44100*2*2 = 176400字节
		a.duration = float64(fileInfo.Size()) / 176400.0
	}

	// 构建aplay命令
	aplayPath := a.config.PlayerPath
	if aplayPath == "" {
		aplayPath = "aplay"
	}

	a.cmd = exec.CommandContext(ctx, aplayPath, "-q", source.Path)

	// 启动命令
	err = a.cmd.Start()
	if err != nil {
		a.status = audioplayer.StatusError
		return fmt.Errorf("启动aplay失败: %v", err)
	}

	// 设置状态为播放中
	a.status = audioplayer.StatusPlaying

	// 触发播放开始事件
	a.triggerEvent(audioplayer.EventPlaybackStarted)

	// 异步等待命令完成
	go func() {
		err := a.cmd.Wait()
		a.mutex.Lock()
		defer a.mutex.Unlock()

		// 如果是正常结束（而非被中断）
		if err == nil && a.status == audioplayer.StatusPlaying {
			a.status = audioplayer.StatusStopped
			a.position = 0
			a.source = nil
			a.cmd = nil

			// 触发播放完成事件
			a.triggerEvent(audioplayer.EventPlaybackCompleted)

			// 播放结束后自动播放下一首
			if a.config.AutoPlayNext && len(a.playlist) > 0 {
				// 解锁后再调用，避免死锁
				a.mutex.Unlock()
				a.PlayNext(context.Background())
				a.mutex.Lock()
			}
		}
	}()

	return nil
}

// Pause 暂停播放
func (a *APlayAdapter) Pause(ctx context.Context) error {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	if a.status != audioplayer.StatusPlaying || a.cmd == nil || a.cmd.Process == nil {
		return fmt.Errorf("没有可暂停的活跃播放")
	}

	// 记录暂停时间点
	a.pausedAt = time.Now()

	// 发送SIGSTOP信号暂停进程
	err := a.cmd.Process.Signal(syscall.SIGSTOP)
	if err != nil {
		return fmt.Errorf("无法暂停播放: %v", err)
	}

	a.status = audioplayer.StatusPaused

	// 触发暂停事件
	a.triggerEvent(audioplayer.EventPlaybackPaused)

	return nil
}

// Resume 从暂停状态恢复播放
func (a *APlayAdapter) Resume(ctx context.Context) error {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	if a.status != audioplayer.StatusPaused || a.cmd == nil || a.cmd.Process == nil {
		return fmt.Errorf("没有可恢复的暂停播放")
	}

	// 计算累计暂停时间
	pauseDuration := time.Since(a.pausedAt)
	a.totalPausedTime += pauseDuration

	// 发送SIGCONT信号恢复进程
	err := a.cmd.Process.Signal(syscall.SIGCONT)
	if err != nil {
		return fmt.Errorf("无法恢复播放: %v", err)
	}

	a.status = audioplayer.StatusPlaying

	// 触发恢复事件
	a.triggerEvent(audioplayer.EventPlaybackResumed)

	return nil
}

// Stop 停止播放
func (a *APlayAdapter) Stop(ctx context.Context) error {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	err := a.stopPlayback()
	if err == nil {
		// 触发停止事件
		a.triggerEvent(audioplayer.EventPlaybackStopped)
	}

	return err
}

// 内部方法，在已获取锁的情况下停止播放
func (a *APlayAdapter) stopPlayback() error {
	if a.cmd != nil && a.cmd.Process != nil {
		// 发送终止信号给aplay进程
		err := a.cmd.Process.Signal(syscall.SIGTERM)
		if err != nil {
			// 如果无法发送SIGTERM，尝试强制终止
			a.cmd.Process.Kill()
		}
		a.cmd = nil
	}

	a.status = audioplayer.StatusStopped
	a.position = 0
	a.source = nil
	return nil
}

// IsPlaying 返回当前是否正在播放
func (a *APlayAdapter) IsPlaying() bool {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	return a.status == audioplayer.StatusPlaying
}

// Seek 跳转到指定位置（注意：aplay不直接支持seek，这里实现将重新播放至指定位置）
func (a *APlayAdapter) Seek(ctx context.Context, position float64) error {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	if a.source == nil {
		return fmt.Errorf("没有正在播放的文件")
	}

	// 由于aplay不支持seek，这里的实现是重新播放原文件
	// 保存当前播放文件
	source := *a.source

	// 停止当前播放
	a.stopPlayback()

	// 重新开始播放
	a.mutex.Unlock()
	err := a.Play(ctx, source)
	a.mutex.Lock()

	if err != nil {
		return fmt.Errorf("无法跳转到指定位置: %v", err)
	}

	// 注意：这个seek实现不准确，因为aplay不支持从指定位置播放
	// 在实际应用中应考虑使用支持seek的库或工具

	// 触发位置改变事件
	a.triggerEvent(audioplayer.EventPositionChanged)

	return nil
}

// GetPosition 获取当前播放位置
func (a *APlayAdapter) GetPosition() float64 {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	// 计算当前位置
	if a.status == audioplayer.StatusPlaying && a.source != nil {
		playTime := time.Since(a.startTime) - a.totalPausedTime
		a.position = playTime.Seconds()

		// 防止位置超过总时长
		if a.position > a.duration && a.duration > 0 {
			a.position = a.duration
		}
	}

	return a.position
}

// GetDuration 获取当前音频总长度
func (a *APlayAdapter) GetDuration() float64 {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	return a.duration
}

// SetVolume 设置音量
func (a *APlayAdapter) SetVolume(volume float64) error {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	// 范围限制为0.0-1.0
	if volume < 0 {
		volume = 0
	}
	if volume > 1.0 {
		volume = 1.0
	}

	// 将0.0-1.0范围转换为百分比
	volumePercent := int(volume * 100)

	// 调用amixer设置主音量
	cmd := exec.Command("amixer", "set", "Master", fmt.Sprintf("%d%%", volumePercent))
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("设置音量失败: %v", err)
	}

	a.volume = volume
	return nil
}

// GetVolume 获取当前音量
func (a *APlayAdapter) GetVolume() float64 {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	return a.volume
}

// GetPlaybackInfo 获取当前播放信息
func (a *APlayAdapter) getPlaybackInfo() audioplayer.PlaybackInfo {
	// 计算当前位置
	if a.status == audioplayer.StatusPlaying && a.source != nil {
		playTime := time.Since(a.startTime) - a.totalPausedTime
		a.position = playTime.Seconds()

		// 防止位置超过总时长
		if a.position > a.duration && a.duration > 0 {
			a.position = a.duration
		}
	}

	info := audioplayer.PlaybackInfo{
		Status:   a.status,
		Position: a.position,
		Duration: a.duration,
		Volume:   a.volume,
		Source:   a.source,
	}

	return info
}

// GetPlaybackInfo 获取当前播放信息
func (a *APlayAdapter) GetPlaybackInfo() audioplayer.PlaybackInfo {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	return a.getPlaybackInfo()
}

// AddToPlaylist 添加文件到播放列表
func (a *APlayAdapter) AddToPlaylist(source audioplayer.AudioSource) error {
	a.playlistMutex.Lock()
	defer a.playlistMutex.Unlock()

	// 检查文件是否存在
	if _, err := os.Stat(source.Path); os.IsNotExist(err) {
		return fmt.Errorf("文件不存在: %s", source.Path)
	}

	// 复制AudioSource以确保不会被外部修改
	sourceCopy := source

	// 添加到播放列表
	a.playlist = append(a.playlist, &sourceCopy)
	return nil
}

// RemoveFromPlaylist 从播放列表移除文件
func (a *APlayAdapter) RemoveFromPlaylist(index int) error {
	a.playlistMutex.Lock()
	defer a.playlistMutex.Unlock()

	if index < 0 || index >= len(a.playlist) {
		return fmt.Errorf("播放列表索引超出范围: %d", index)
	}

	// 移除指定索引的项
	a.playlist = append(a.playlist[:index], a.playlist[index+1:]...)
	return nil
}

// ClearPlaylist 清空播放列表
func (a *APlayAdapter) ClearPlaylist() error {
	a.playlistMutex.Lock()
	defer a.playlistMutex.Unlock()

	a.playlist = make([]*audioplayer.AudioSource, 0)
	return nil
}

// GetPlaylist 获取当前播放列表
func (a *APlayAdapter) GetPlaylist() ([]audioplayer.AudioSource, error) {
	a.playlistMutex.RLock()
	defer a.playlistMutex.RUnlock()

	// 创建副本以避免并发修改问题
	playlist := make([]audioplayer.AudioSource, len(a.playlist))
	for i, source := range a.playlist {
		playlist[i] = *source
	}

	return playlist, nil
}

// PlayNext 播放下一曲
func (a *APlayAdapter) PlayNext(ctx context.Context) error {
	a.playlistMutex.RLock()

	if len(a.playlist) == 0 {
		a.playlistMutex.RUnlock()
		return fmt.Errorf("播放列表为空")
	}

	// 找到当前播放文件的索引
	currentIndex := -1
	currentSource := a.GetPlaybackInfo().Source

	if currentSource != nil {
		for i, source := range a.playlist {
			if source.Path == currentSource.Path {
				currentIndex = i
				break
			}
		}
	}

	// 确定下一曲的索引
	nextIndex := 0
	if currentIndex >= 0 && currentIndex < len(a.playlist)-1 {
		nextIndex = currentIndex + 1
	}

	// 获取下一曲
	source := *a.playlist[nextIndex]
	a.playlistMutex.RUnlock()

	// 播放下一曲
	return a.Play(ctx, source)
}

// PlayPrevious 播放上一曲
func (a *APlayAdapter) PlayPrevious(ctx context.Context) error {
	a.playlistMutex.RLock()

	if len(a.playlist) == 0 {
		a.playlistMutex.RUnlock()
		return fmt.Errorf("播放列表为空")
	}

	// 找到当前播放文件的索引
	currentIndex := -1
	currentSource := a.GetPlaybackInfo().Source

	if currentSource != nil {
		for i, source := range a.playlist {
			if source.Path == currentSource.Path {
				currentIndex = i
				break
			}
		}
	}

	// 确定上一曲的索引
	prevIndex := len(a.playlist) - 1 // 默认循环到最后一首
	if currentIndex > 0 {
		prevIndex = currentIndex - 1
	}

	// 获取上一曲
	source := *a.playlist[prevIndex]
	a.playlistMutex.RUnlock()

	// 播放上一曲
	return a.Play(ctx, source)
}

// GetSupportedFormats 获取支持的音频格式
func (a *APlayAdapter) GetSupportedFormats() []audioplayer.AudioFormat {
	// 深拷贝避免外部修改
	formats := make([]audioplayer.AudioFormat, len(a.supportedFormats))
	copy(formats, a.supportedFormats)
	return formats
}

// RegisterEventHandler 注册事件处理函数
func (a *APlayAdapter) RegisterEventHandler(eventType audioplayer.PlaybackEventType, handler audioplayer.PlaybackEventHandler) {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	handlers, exists := a.eventHandlers[eventType]
	if !exists {
		handlers = make([]audioplayer.PlaybackEventHandler, 0)
	}

	a.eventHandlers[eventType] = append(handlers, handler)
}

// UnregisterEventHandler 注销事件处理函数
func (a *APlayAdapter) UnregisterEventHandler(eventType audioplayer.PlaybackEventType, handler audioplayer.PlaybackEventHandler) {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	handlers, exists := a.eventHandlers[eventType]
	if !exists {
		return
	}

	// 移除匹配的处理函数
	for i, h := range handlers {
		// 由于函数无法直接比较，这里只能移除所有处理函数
		// 实际应用中可以通过标识符或闭包实现更精确的移除
		if fmt.Sprintf("%p", h) == fmt.Sprintf("%p", handler) {
			a.eventHandlers[eventType] = append(handlers[:i], handlers[i+1:]...)
			break
		}
	}
}

// Initialize 初始化播放器
func (a *APlayAdapter) Initialize() error {
	// 已经在构造函数中完成了基本初始化
	return nil
}

// Close 关闭播放器并释放资源
func (a *APlayAdapter) Close() error {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	// 停止当前播放
	if a.cmd != nil && a.cmd.Process != nil {
		a.cmd.Process.Kill()
		a.cmd = nil
	}

	a.status = audioplayer.StatusStopped
	return nil
}

// 触发事件
func (a *APlayAdapter) triggerEvent(eventType audioplayer.PlaybackEventType) {
	handlers, exists := a.eventHandlers[eventType]
	if !exists || len(handlers) == 0 {
		logger.SystemInfo("没有事件处理函数")
		return
	}

	// 创建事件
	event := audioplayer.PlaybackEvent{
		Type:      eventType,
		Info:      a.getPlaybackInfo(),
		Timestamp: time.Now(),
	}

	// 调用所有处理函数
	for _, handler := range handlers {
		go handler(event) // 异步调用，避免阻塞
	}
}
